/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 电子商务云服务平台
 * 创建日期 : 2016年6月28日
 * 修改历史 : 
 *     1. [2016年6月30日]修改文件 by chihouliang
 * 添加Javadoc注释，更新代码规范，静态工具类增加private构造函数<br/>
 * 增加方法createFile
 */
package com.gavinwind.inspay.common.util;

import com.gavinwind.inspay.common.logger.PlatformLogger;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 文件操作工具类，提供处理文件上传服务器，从服务器下载
 * 
 * @date 2010-11-24
 * @since JDK 1.5
 * @author dingkui
 * @version 1.0
 */
public class FileUtil extends FileUtils {
    /**日志*/
    private static PlatformLogger logger = PlatformLogger.getLogger(FileUtil.class);

    private FileUtil() {
    }

    /**
     * 使用HttpClient上传文件到远程http服务端
     * 
     * @param cUploadUrl
     *            前台上传文件到后台请求的url
     * @param cFilePath
     *            本地文件绝对路径（包括文件名）
     * @return tStatusCode 远程http服务端返回的状态
     * @throws java.io.IOException
     *             IO异常
     */
    public static int httpClientUpload(String cUploadUrl, String cFilePath) throws IOException {
        int tStatus = 0;
        PostMethod tPostMethod = null;

        try {
            tPostMethod = new PostMethod(cUploadUrl);
            // 通过以下方法可以模拟页面参数提交
            File tRargetFile = new File(cFilePath);
            Part[] tParts = { new FilePart(tRargetFile.getName(), tRargetFile) };
            tPostMethod.setRequestEntity(new MultipartRequestEntity(tParts, tPostMethod.getParams()));
            HttpClient tClient = new HttpClient();

            tClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);

            tStatus = tClient.executeMethod(tPostMethod);
            tPostMethod.releaseConnection();
        } catch (HttpException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } finally {
            if (tPostMethod != null) {
                tPostMethod.releaseConnection();
            }
        }
        return tStatus;
    }

    /**
     * HttpClient下载文件
     *
     * @param cDownloadUrl
     *            前台下载后台文件请求的url
     * @param cFileName
     *            文件名称
     * @param cFilePath
     *            文件保存在前台的绝对路径（包括文件名）
     * @param cLocalFilePath
     *            文件下载到前台的路径（文件的保存路径）
     * @param cParameter
     *            用HashMap给PostMethod传参数
     * @return tStatusCode 远程http服务端返回的状态
     * @throws java.io.IOException
     */
    public static int httpClientDownload(String cDownloadUrl, String cFileName, String cLocalFilePath, String cFilePath,
            HashMap<String, String> cParameter) throws IOException {
        HttpClient tHttpClient = new HttpClient();
        PostMethod tPostMethod = new PostMethod(cDownloadUrl);

        if (cParameter != null && cParameter.size() > 0) {
            Set<String> tKeySet = cParameter.keySet();
            for (String tStr : tKeySet) {
                tPostMethod.setParameter(tStr, cParameter.get(tStr));
            }
        }

        int tStatusCode = 0;
        OutputStream tOutputStream = null;
        try {
            tStatusCode = tHttpClient.executeMethod(tPostMethod);
            if (tStatusCode == HttpStatus.SC_OK) {
                File tPath = new File(cLocalFilePath);
                if (!tPath.exists()) {
                    tPath.mkdir();
                }
                // 读取内容
                byte[] tResponseBody = tPostMethod.getResponseBody();
                tOutputStream = new FileOutputStream(new File(cFilePath));
                tOutputStream.write(tResponseBody);
                tOutputStream.flush();
                tOutputStream.close();
            }

        } catch (HttpException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } finally {
            if (tOutputStream != null) {
                tOutputStream.close();
            }
        }
        return tStatusCode;
    }

    /**
     * 接收上传文件，并保存到本地
     *
     * @param cRequest
     *            页面request请求
     * @param cSizeThreshold
     *            内存中缓冲区大小
     * @param cSizeMax
     *            最大文件限制
     * @param cLocalFilePath
     *            本地文件路径
     * @param cLocalFileName
     *            本地保存的文件名
     */
    @SuppressWarnings("unchecked")
    public static void tUpload(HttpServletRequest cRequest, int cSizeThreshold, int cSizeMax, String cLocalFilePath, String cLocalFileName) {

        DiskFileItemFactory tFactory = new DiskFileItemFactory();
        tFactory.setSizeThreshold(cSizeThreshold);
        ServletFileUpload tUpload = new ServletFileUpload(tFactory);
        tUpload.setSizeMax(cSizeMax);
        List<FileItem> tItems;
        try {
            tItems = tUpload.parseRequest(cRequest);
        } catch (FileUploadException e) {
            e.printStackTrace();
            throw new RuntimeException("处理上传文件发生异常");
        }
        Iterator<FileItem> tItr = tItems.iterator();
        while (tItr.hasNext()) {
            FileItem tItem = (FileItem) tItr.next();
            String tFileName = tItem.getName();
            if (tFileName != null) {
                // 前台保存路径不存在，创建
                File tPath = new File(cLocalFilePath);
                if (!tPath.exists()) {
                    tPath.mkdir();
                }
                File tFile = new File(cLocalFilePath, cLocalFileName);
                try {
                    tItem.write(tFile);
                } catch (Exception e) {
                    throw new RuntimeException("从上传文件流中，输出内容到文件时发生异常");
                }
            }
        }
    }

    /**
     * 从本地下载文件。将文件放入response，返回给客户端浏览器
     *
     * @param cResponse
     *            页面响应
     * @param cFilePath
     *            文件保存在前台的绝对路径（包括文件名）
     * @param cFileName
     *            文件名称
     * @throws java.io.IOException
     *             IO异常
     */
    public static void download(HttpServletResponse cResponse, String cFilePath, String cFileName) throws IOException {
        InputStream tInputStream = null;
        try {
            tInputStream = new FileInputStream(cFilePath);
            // 设置输出的格式
            cResponse.reset();
            cResponse.setContentType("application/x-msdownload");
            cResponse.setCharacterEncoding("UTF-8");
            String tFilename = new String(cFileName.getBytes("GBK"), "ISO8859_1");
            cResponse.addHeader("Content-Disposition", "attachment; filename=\"" + tFilename + "\"");
            // 循环取出流中的数据
            byte[] tByteArr = new byte[1024];
            int tLen;
            while ((tLen = tInputStream.read(tByteArr)) > 0)
                cResponse.getOutputStream().write(tByteArr, 0, tLen);
            tInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("处理下载文件时发生IO异常");
        } finally {
            if (tInputStream != null) {
                tInputStream.close();
            }
        }
    }

    /**
     * 拷贝输入流到一个文件中
     * @Title: copyInputStreamToFile
     * @param cSource 需要拷贝的文件流
     * @param cDestination 拷贝后的文件，目标文件
     * @throws java.io.IOException IO异常
     */
    public static void copyInputStreamToFile(InputStream cSource, File cDestination) throws IOException {
        try {
            FileOutputStream tOutput = openOutputStream(cDestination);
            try {
                IOUtils.copy(cSource, tOutput);
                tOutput.close();
            } finally {
                IOUtils.closeQuietly(tOutput);
            }
        } finally {
            IOUtils.closeQuietly(cSource);
        }
    }

    /**
     * 
     * 把文本内容生成本地文件
     * @param cPath 本地路径，相对路径或绝对路径
     * @param cContent 文件内容
     * @param cCharset 编码格式，如果为空，默认使用UTF-8
     */
    public static void createFile(String cPath, String cContent, String cCharset) {
        File tFile = new File(cPath);
        //当文件不存在时候，创建文件。创建失败的原因可能会是路径不正确，权限不足
        if (!tFile.exists()) {
            try {
                tFile.createNewFile();
            } catch (IOException e) {
                logger.info("文件创建失败" + e);
                return;
            }
        }

        OutputStream tOutputStream = null;
        try {
            
            tOutputStream = new FileOutputStream(tFile);
            byte[] tByteArr = cContent.getBytes(cCharset);
            tOutputStream.write(tByteArr);

        } catch (IOException e) {
            logger.info("文件生成失败" + e);
        } finally {
            closeOutputStream(tOutputStream);
        }

    }
 
    /**
     * 
     * 把文本内容生成本地文件，使用utf-8解析文本内容
     * @param cPath 本地路径，相对路径或绝对路径
     * @param cContent 文件内容
     */
    public static void createFile(String cPath, String cContent){
        createFile(cPath,cContent,null);
    }

    /**
     * 
     * 关闭文件输入流，记录日志
     * @param cInputStream 文件输入流
     * @history 
     *   1 add  by chihouliang 2016年6月30日
     */
    public static void closeInputStream(InputStream cInputStream){
        if(cInputStream != null){
            try {
                cInputStream.close();
            } catch (IOException e) {
                logger.error("FileUtil系统异常:",e);
            }
        }
    }
    
    /**
     * 
     * 关闭文件输出流，异常记录日志
     * @param cOutputStream 文件输出流
     */
    public static void closeOutputStream(OutputStream cOutputStream){
        if(cOutputStream!=null){
            try {
                cOutputStream.close();
            } catch (IOException e) {
                logger.error("FileUtil系统异常:",e);
            }
        }
    }
    
}
